package com.owen.blog.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.owen.blog.dao.LabelToBlogDao;
import com.owen.blog.domain.LabelToBlog;
import com.owen.blog.vo.AesPasswordVO;
import com.owen.common.config.ProjectConfig;
import com.owen.common.utils.AESUtil;
import com.owen.common.utils.SnowflakeIdWorker;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.owen.blog.dao.ContentDao;
import com.owen.blog.domain.ContentDO;
import com.owen.blog.service.ContentService;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

@Service
public class ContentServiceImpl implements ContentService {

	@Value("${owen.aes.password}")
	private String aesPassword;

	@Autowired
	private ProjectConfig projectConfig;

	@Autowired
	private ContentDao bContentMapper;

	@Autowired
	private LabelToBlogDao labelToBlogDao;

	// 雪花算法生成
	@Autowired
	private SnowflakeIdWorker snowflakeIdWorker;

	@Override
	public ContentDO get(String cid){
		return bContentMapper.get(cid);
	}

	@Override
	public List<ContentDO> list(Map<String, Object> map){
		return bContentMapper.list(map);
	}

	@Override
	public int count(Map<String, Object> map){
		return bContentMapper.count(map);
	}

	@Override
	@Transactional
	public int save(ContentDO bContent) {
		bContent.setCid(snowflakeIdWorker.nextIdStr());
		List<String> blogLabelIds = bContent.getBlogLabelIds();
		if (CollectionUtil.isNotEmpty(blogLabelIds)) {
			List<LabelToBlog> labelToBlogs = new ArrayList<LabelToBlog>();
			for (String blogLabel : blogLabelIds) {
				LabelToBlog labelToBlog = new LabelToBlog();
				labelToBlog.setId(snowflakeIdWorker.nextIdStr());
				labelToBlog.setBlogContentId(bContent.getCid());
				labelToBlog.setBlogLabelId(blogLabel);
				labelToBlogs.add(labelToBlog);
			}
			labelToBlogDao.batchSave(labelToBlogs);
		}
		return bContentMapper.save(bContent);
	}

	@Override
	@Transactional
	public int update(ContentDO bContent){
		labelToBlogDao.removeByBlogContentId(bContent.getCid());
		List<String> blogLabelIds = bContent.getBlogLabelIds();
		if (CollectionUtil.isNotEmpty(blogLabelIds)) {
			List<LabelToBlog> labelToBlogs = new ArrayList<LabelToBlog>();
			for (String blogLabel : blogLabelIds) {
				LabelToBlog labelToBlog = new LabelToBlog();
				labelToBlog.setId(snowflakeIdWorker.nextIdStr());
				labelToBlog.setBlogContentId(bContent.getCid());
				labelToBlog.setBlogLabelId(blogLabel);
				labelToBlogs.add(labelToBlog);
			}
			labelToBlogDao.batchSave(labelToBlogs);
		}
		return bContentMapper.update(bContent);
	}

	@Override
	@Transactional
	public int remove(String cid){
		labelToBlogDao.removeByBlogContentId(cid);
		return bContentMapper.remove(cid);
	}

	@Override
	@Transactional
	public int batchRemove(String[] cids){
		for (String cid : cids) {
			labelToBlogDao.removeByBlogContentId(cid);
		}
		return bContentMapper.batchRemove(cids);
	}

	@Override
	public AesPasswordVO randomPassWord() {
		String randomPassWord = RandomUtil.randomString(50);
        try {
			String encrypt = AESUtil.encrypt(randomPassWord, aesPassword);
			AesPasswordVO aesPasswordVO = new AesPasswordVO();
			aesPasswordVO.setPassword(randomPassWord);
			aesPasswordVO.setAesPassword(encrypt);
			return aesPasswordVO;
		} catch (Exception e) {
            throw new RuntimeException(e);
        }
	}

	@Override
	public void download(String cid, HttpServletResponse response) {
		Assert.isTrue(ObjectUtil.isNotEmpty(cid), "文章id未获取到，无法下载");
		ContentDO content = bContentMapper.get(cid);
		Assert.isTrue(ObjectUtil.isNotEmpty(content), "文章数据获取失败");
		// 源码文件存放路径
		String sourceCode = content.getSourceCode();
		Assert.isTrue(ObjectUtil.isNotEmpty(sourceCode), "该文章无可下载源码");
		// 文件存住根路径
		String uploadPath = projectConfig.getUploadPath();
		if (uploadPath.endsWith("/")){
			// 去除最后结尾的文件分割符
			uploadPath = uploadPath.substring(0,uploadPath.length()-1);
		}
		// 源码文件所在磁盘路径
		String sourceCodePath = uploadPath + sourceCode;
		Assert.isTrue(FileUtil.isFile(sourceCodePath), "下载源码错误，源码文件不存在！");

		// 将要下载给用户文件的文件
		String downloadFileName = ObjectUtil.isNotEmpty(content.getSourceCodeFileName()) ? content.getSourceCodeFileName() : FileUtil.getName(sourceCodePath);
        try (InputStream is = Files.newInputStream(Paths.get(sourceCodePath));
			 	ServletOutputStream os = response.getOutputStream()){
			response.setContentType("application/octet-stream");
			response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(downloadFileName, "UTF-8"));
			IOUtils.copy(is, os);
			// 自增一次源码下载次数
			bContentMapper.updateSourceDownloadCountIncr(cid);
		} catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
